unit IFMTextSpoolerUnit;

interface

uses types, classes, sysutils, clipbrd;

   type TCharSet = set of char;
   PgTextSpooler = class
   private
      m_Delim : TCharSet;
      m_Cell : string;
      m_Col, m_Row : Integer;
      function StartOver(_Col, _Row : Integer) : Boolean;
   protected
      m_Stream : TStream;
      function OnCellRead : Boolean; virtual;
   public
      function Spool(_Col : Integer = -1; _Row : Integer = -1) : Boolean; virtual;
      constructor Create(Delim : TCharSet = [#9]; UseClipboard : Boolean = true; FileName : string = ''; Resource : string = ''); reintroduce;
      destructor Destroy; override;
      property Row : Integer read m_Row write m_Row;
      property Col : Integer read m_Col write m_Col;
      property Cell : string read m_Cell write m_Cell;
   end;


implementation


//////////////////////////////
// PgTextSpooler


function PgTextSpooler.OnCellRead : Boolean;
begin
   Result := true;
end;


function PgTextSpooler.StartOver(_Col, _Row : Integer) : Boolean;
begin
   Result := (((0 <= _Col) and (0 <= _Row)) and ((_Row < Row) or ((_Row = Row) and (_Col < Col)))) or
      ((_Col < 0) and (0 <= _Row) and (_Row < Row));
end; // PgTextSpooler.StartOver


function SkipChar(c : char) : Boolean;
begin
   case c of
      #$D, '"', '''':
         Result := true;
   else
      Result := false;
   end;
end; // SkipChar


function PgTextSpooler.Spool(_Col, _Row : Integer) : Boolean;
var
   c : char;
begin
   Cell := '';
   Result := false;
   if StartOver(_Col, _Row) then
   begin
      Col := 0;
      Row := 0;
      m_Stream.Seek(0, soFromBeginning);
   end;
   with m_Stream do
      repeat
         if 0 = Read(c, 1) then
         begin
            Result := true;
            if Cell <> '' then
               OnCellRead;
            break;
         end;
         if (c in m_Delim) or (c = #$A) then
         begin
            if ((_Col = -1) or (_Col = Col)) and ((_Row = -1) or (_Row = Row)) and not OnCellRead then
               break;
            if (c in m_Delim) then
               Inc(m_Col)
            else
            begin
               // line feed
               Inc(m_Row);
               Col := 0;
            end;
            if StartOver(_Col, _Row) then
               break;
            Cell := '';
         end
         else
            if not SkipChar(c) then
            begin
(*               if integer(c) = 32 then
                  Add := ' '
               else
                  Add := trim(string(c));*)
               Cell := Cell + c;
            end;
      until false;
end; // PgTextSpooler.Spool


constructor PgTextSpooler.Create(Delim : TCharSet; UseClipboard : Boolean; FileName : string; Resource : string);
begin
   inherited Create;
   Col := 0;
   Row := 0;
   m_Delim := Delim;
   if Resource <> '' then
      m_Stream := TResourceStream.Create(hinstance, Resource, RT_RCDATA)
   else
   begin
      if UseClipboard then
         m_Stream := TStringStream.Create(Clipboard.AsText)
      else
         m_Stream := TFileStream.Create(FileName, fmOpenRead + fmShareDenyNone);
   end;
   m_Stream.Seek(0, soFromBeginning);
end; // PgTextSpooler.Create


destructor PgTextSpooler.Destroy;
begin
   inherited;
   m_Stream.Free;
end; // PgTextSpooler.Destroy


end.
